package org.trc.network;

import java.awt.Rectangle;
import java.util.ArrayList;
import com.vividsolutions.jts.geom.Envelope;
import com.vividsolutions.jts.geom.Point;

/**
 * 
 * @author Lin Xu
 *
 */

public class Node extends Graphable {
    public String id; 
    public Point point; 
    
    public AdjEdge_Entry[] adjEdge_Entries = new AdjEdge_Entry[4]; //邻接表
    
   //TODO: public ArrayList <AdjEdge_Entry> adjEdgeList = new ArrayList <AdjEdge_Entry> ();
    
    public int numOfEdge = 0; //度
    public float[][] turnMatrix;//转向矩阵（概率）
    public int turnCount = 0;
    
    public class AdjEdge_Entry { //邻接表元素
        String adjNode_id; //邻近节点ID
        String adjEdge_id; //邻近路段ID
        double weight;
        int direction; //单向或双向路，双向为0，单向离开1，单向进入2 (同时表达几何上连通，逻辑上连通)
        
        public AdjEdge_Entry(String adjNode_id, String adjEdge_id, double weight,int direction) {
            this.adjNode_id = adjNode_id;
            this.adjEdge_id = adjEdge_id;
            this.weight = weight;
            this.direction = direction;
        }
    }

    //构造器
    public Node(String id, Point point) {
        this.id = id;
        this.point = point;
    }
	
	//初始化节点转向矩阵
    public void initTurnMatrix() {
        float[][] turnMatrix = new float[this.numOfEdge][this.numOfEdge];
        for (int i = 0; i < numOfEdge; i++) {
        	for (int j = 0; j < turnMatrix[i].length; j++) {
        		turnMatrix[i][j] = 0; //将所有的转向统计归零
//        		if (j == i) {
//        			turnMatrix[i][j] = 0; //静止U-turn的转向
//        		} else {
//        			turnMatrix[i][j] = 1;
//        		}
            }
        }
    }
    
    public String getID() {
        return id;
    }

    public int getDegree() {
        return this.numOfEdge;
    }
    
    public int[] getPoint() {
        int x = (int) point.getX();
        int y = (int) point.getY();
        return new int[] {x, y};
    }

    public Rectangle getMBR() {
        Envelope en = point.getEnvelopeInternal();
        return new Rectangle((int) en.getMinX(), (int) en.getMinY(),(int) en.getWidth(), (int) en.getHeight());
    }

    //加入邻接路段(构建邻接表)
    public void addEdge(Edge edge) {
        String another_nodeId = edge.getAnotherNodeId(this.id);
        String edgeId = edge.id;
        int direction = 0;
        
        if(edge.direction != 0 && edge.direction != 1) // 非双向路
        	direction = edge.direction;
        else if (this.id.equals(edge.startNodeID))
        	direction = 2;
        else 
        	direction = 3;
        
        AdjEdge_Entry newEntry = new AdjEdge_Entry(another_nodeId, edgeId, edge.length, direction);
        if (numOfEdge >= adjEdge_Entries.length) {
            AdjEdge_Entry[] newEntries = new AdjEdge_Entry[2 * adjEdge_Entries.length];
            for (int i = 0; i < adjEdge_Entries.length; i++) {
                newEntries[i] = adjEdge_Entries[i];
            }
            adjEdge_Entries = newEntries;
        }
        adjEdge_Entries[numOfEdge++] = newEntry;
    }

    //加入转向限制
    public void addNoTurn(String fromEdgeID, String toEdgeID) {
        int in_order = this.index_TurnMatrix(fromEdgeID);
        int out_order = this.index_TurnMatrix(toEdgeID);
        if (in_order == this.numOfEdge || out_order == this.numOfEdge) {
            return;
        }
        this.turnMatrix[in_order][out_order] = 0;
    }

    //加入一次转向计数
	public void addOneTurn(String fromEdgeID, String toEdgeID){
        int in_order = this.index_TurnMatrix(fromEdgeID);
        int out_order = this.index_TurnMatrix(toEdgeID);
        this.turnMatrix[in_order][out_order] = this.turnMatrix[in_order][out_order] + 1;
        this.turnCount++;
	}
	
	//获取转向统计信息
	public int getTurnCount(String fromEdgeId, String toEdgeId){
		int in_order = this.index_TurnMatrix(fromEdgeId);
		int out_order = this.index_TurnMatrix(toEdgeId);
		return (int)this.turnMatrix[in_order][out_order];
	}
	
	public float getTurnProbility(String fromEdgeId, String toEdgeId){
		int count = (int)this.turnMatrix[this.index_TurnMatrix(fromEdgeId)][this.index_TurnMatrix(toEdgeId)];
		int sum = 0;
		int i = this.index_TurnMatrix(fromEdgeId);
		for(int j = 0 ; j < this.numOfEdge ; j++){
			sum += this.turnMatrix[i][j];
		}
		if(count == 0)
			return 0;
		return (float)count/(float)sum;
	}
	
	public void setTurnProbility(String fromEdgeId, String toEdgeId, float probility){
		int row = this.index_TurnMatrix(fromEdgeId);
		int column = this.index_TurnMatrix(toEdgeId);
		this.turnMatrix[row][column] = probility;
		
	}
	
    //获取邻接路段
	public String getEdge(String adjNodeId){
		for(AdjEdge_Entry adjEntry : adjEdge_Entries){
			if(adjEntry.adjNode_id.equals(adjNodeId))
				return adjEntry.adjEdge_id;
//			    break;
		}
		return null;
	}
	
    public String[] getAdjEdges() {
        ArrayList<String> edges = new ArrayList<String>(4);
        for (int i = 0; i < this.numOfEdge; i++) {
            edges.add(adjEdge_Entries[i].adjEdge_id);
        }
        return edges.toArray(new String[] {});
    }

    public String[] getAdjEdges(String edgeId) {
        ArrayList<String> adjEdges = new ArrayList<String>();
        for (int i = 0; i < this.numOfEdge; i++) {
            if (!adjEdge_Entries[i].adjEdge_id.equals(edgeId)) {
                adjEdges.add(adjEdge_Entries[i].adjEdge_id);
            }
        }
        return adjEdges.toArray(new String[] {});
    }

    //获取邻接节点
    public String[] getAdjNodes() {
        ArrayList<String> nodes = new ArrayList<String>(4);
        for (int i = 0; i < this.numOfEdge; i++) {
            nodes.add(adjEdge_Entries[i].adjNode_id);
        }
        return nodes.toArray(new String[] {});
    }
    
    //获取邻接边权重
    public double getAdjEdgeWeight(String adjNodeId){
		for(AdjEdge_Entry adjEntry : adjEdge_Entries){
			if(adjEntry.adjNode_id.equals(adjNodeId))
				return adjEntry.weight;
			//break;
		}
		//设计异常类
		return Double.MAX_VALUE;
    }
    
    //所有进入路段
    public Arc[] in_Arcs() {
        ArrayList<Arc> inArcs = new ArrayList<Arc>(4);
        for (int i = 0; i < this.numOfEdge; i++) {
            if (adjEdge_Entries[i].direction != 1) {
                inArcs.add(new Arc(adjEdge_Entries[i].adjEdge_id, adjEdge_Entries[i].adjNode_id, this.getID()));
            }
        }
        return inArcs.toArray(new Arc[] {});
    }

    //所有离开路段
    public Arc[] out_Arcs() {
        ArrayList<Arc> outArcs = new ArrayList<Arc>(4);
        for (int i = 0; i < this.numOfEdge; i++) {
            if (adjEdge_Entries[i].direction != 2) {
                outArcs.add(new Arc(adjEdge_Entries[i].adjEdge_id, this.getID(), adjEdge_Entries[i].adjNode_id));
            }
        }
        return outArcs.toArray(new Arc[] {});
    }

    //指定路段的邻近可进入路段(转向限制)
    public Arc[] in_Arcs(Arc outArc) {
        int index = this.index_TurnMatrix(outArc.edgeId); //找到指定边在邻接表中的序号
        ArrayList<Arc> inArcs = new ArrayList<Arc>(3);
        if (index == numOfEdge) { //无法找到该弧段
            return null;
        }
        String edgeId = null; //查找进入弧段id
        String startNodeId = null; //查找进入弧段起点
        String endNodeId = null; //查找进入弧段终点
        //查找进入弧段
        for (int i = 0; i < numOfEdge; i++) {
            if (turnMatrix[i][index] != 0) {
                edgeId = this.adjEdge_Entries[i].adjEdge_id;
                startNodeId = this.adjEdge_Entries[i].adjNode_id;
                endNodeId = this.getID();
                inArcs.add(new Arc(edgeId, startNodeId, endNodeId));
            }
        }
        return inArcs.toArray(new Arc[] {});
    }

    //指定路段的邻近可离开路段(转向限制)
    public Arc[] out_Arcs(Arc inArc) {
        int index = this.index_TurnMatrix(inArc.edgeId); //找到指定边在邻接表中的序号
        ArrayList<Arc> outArcs = new ArrayList<Arc>(3);
        if (index == numOfEdge) {
            return null;
        }
        String edgeId = null; //查找离开弧段id
        String startNodeId = null; //查找离开弧段起点
        String endNodeId = null; //查找离开弧段终点
        for (int i = 0; i < numOfEdge; i++) {
            if (turnMatrix[index][i] != 0) {
                edgeId = this.adjEdge_Entries[i].adjEdge_id;
                startNodeId = this.getID();
                endNodeId = this.adjEdge_Entries[i].adjNode_id;
                outArcs.add(new Arc(edgeId, startNodeId, endNodeId));
            }
        }
        return outArcs.toArray(new Arc[] {});
    }

    //返回转向概率最大的边
    public String getMaxProTurnEdgeId(String fromEdgeId){
    	int index = this.index_TurnMatrix(fromEdgeId);
    	int maxTurnProIndex = 0;
    	float maxTurnPro = 0.33f;
    	for(int i = 0; i < numOfEdge; i++){
    		if(turnMatrix[index][i] > maxTurnPro){
    			maxTurnPro = turnMatrix[index][i];
    		    maxTurnProIndex = i;	
    		}
    	}
    	return this.adjEdge_Entries[maxTurnProIndex].adjEdge_id;
    }

    //TODO: 用ArrayList代替数组
    public void removeVirtualAdjEdge(){
    	for(int i = 0;i < numOfEdge; i++){
    		if(this.adjEdge_Entries[i].adjEdge_id.startsWith("v")){
    			this.adjEdge_Entries[i].adjEdge_id = null;
    			numOfEdge--;
    		}
    	}	  	
    }
    
    private int index_TurnMatrix(String edgeId) {
        int order = 0;
        for (; order < numOfEdge; order++) {
            if (adjEdge_Entries[order].adjEdge_id.equals(edgeId)) {
                return order;
            }
        }
        System.out.println("adjacent List error");
        return numOfEdge; //todo:设计一个异常类
    }

    public String toString(){
    	return this.id;
    }
   
}
